COMP3141 Software System Design and Implementation

COMP3141: Software System Design and Implementation

Term 2, 2023

Code and Notes (Week 5 Thursday)

Table of Contents

1 Live code

This is all the code I wrote during the practical. No guarantee that it makes any sense out of context.

module Prac where

import Data.Maybe
import Test.QuickCheck
import Data.List(sort, nub)

{-
            T
      'h' /   \ 'j'
        F      T
   'i' /  \ 'e'
      T    F
't'  /      \ 'l'
    T         F
              \ 'l'
               T
                \ 'o'
                 T

""
"j"
"hi"
"hit"
"hell"
"hello"

after "badly" deleting hello:

            T
      'h' /   \ 'j'
        F      T
   'i' /  \ 'e'
      T    F
't'  /      \ 'l'
    T         F
              \ 'l'
               T
                \ 'o'
                 T
-}

toList :: Trie -> [String]
toList (Trie b ts) =
  first ++ rest where
  first | b         = [""]
        | otherwise = []
  rest = concatMap (\(x,t) -> map (x:) $ toList t) ts

x :: Trie
x = Trie True [('h', Trie False [('i', Trie True [('t', Trie True [])]), ('e', Trie False [('l', Trie False [('l', Trie True [('o', Trie True [])])])])]), ('j', Trie True [])]

data Trie = Trie Bool [(Char,Trie)]
  deriving (Eq,Show)


{- using mapMaybe -}

deleteM :: String -> Trie -> Trie
deleteM "" (Trie b ts) = Trie False ts
deleteM (c:cs) (Trie b ts)
  = Trie b $ mapMaybe (\(c', t) -> 
      if c'==c
    then case deleteM cs t of
         (Trie False []) -> Nothing
         dt -> Just (c', dt)
    else Just (c', t)
    ) ts

delete :: String -> Trie -> Trie
delete "" (Trie b ts) = Trie False ts
delete (c:cs) (Trie b ts)
  = Trie b $ mapMaybe (\(c', t) -> 
      if c'==c
    then (if delete cs t == Trie False []
        then Nothing 
        else Just (c', delete cs t))
    else Just (c', t)
    ) ts


size :: Trie -> Int
size (Trie b ts) = countThis b + sum (map (size.snd) ts)
  where
    countThis True = 1
    countThis False = 0

{-
  Properties of 'delete':

  NOT an involution.

  'insert' is NOT left or right inverse of 'delete'.
  delete s (insert s t) == t -- not always true
  insert s (delete s t) == t -- not alwyas true

  it IS idempotent.
  delete s (delete s t) == delete s t
 -}

genTrie :: Int -> Gen Trie
genTrie 0 = pure $ Trie True []
genTrie n =
  Trie <$> arbitrary <*> (genKeys >>= genSubtries) where
  genKeys :: Gen [Char]
  genKeys = sort . nub <$> (resize 5 . listOf $ elements ['a'..'z'])
  genSubtries :: [Char] -> Gen [(Char,Trie)]
  genSubtries cs =
      zip cs <$> vectorOf (length cs) (genTrie . max 0 $ n-1-length cs)

instance Arbitrary Trie where
  arbitrary = sized $ genTrie . min 15
  shrink (Trie b ts) =
    (Trie b <$> shrinkList (const []) ts) ++
    (Trie b <$> map shrink ts)


{- `single xs` represents a dictionary consisting of only `xs`. -}
single :: String -> Trie
single []     = Trie True []
single (x:xs) = Trie False [(x,single xs)]

{- `insert t xs` inserts the word xs into the dictionary t. -}
insert :: String -> Trie -> Trie
insert [] (Trie _ ts)     = Trie True ts
insert (x:xs) (Trie b ts) =
  case span ((<x) . fst) ts of
    (ts1,[]) -> Trie b $ ts1 ++ [(x,single xs)]
    (ts1,(y,t):ts2)
      | x == y    -> Trie b $ ts1 ++ (x,insert xs t):ts2
      | otherwise -> Trie b $ ts1 ++ (x,single xs):(y,t):ts2




-- some tests for the properties

propInvolution :: String -> Trie -> Bool
propInvolution s t = delete s (delete s t) == t

propInsertRightInverse :: String -> Trie -> Bool
propInsertRightInverse s t = delete s (insert s t) == t

propInsertLeftInverse :: String -> Trie -> Bool
propInsertLeftInverse s t = insert s (delete s t) == t

propIdempotent :: String -> Trie -> Bool
propIdempotent s t = delete s (delete s t) == delete s t

-- check t s == False ==> delete s t == t







-- ADT stuff

{-
            4
          /   \
         1     11
        / \    / \
       L   L  15   L
-} 


-- module SearchTree(SearchTree, wellFormed) where

data SearchTree a = Leaf | Node a (SearchTree a) (SearchTree a)
  deriving (Eq,Show)

stAll :: (a -> Bool) -> SearchTree a -> Bool
stAll _ Leaf = True
stAll f (Node a t1 t2) = f a && stAll f t1 && stAll f t2

wellFormed :: Ord a => SearchTree a -> Bool
wellFormed Leaf = True
wellFormed (Node x t1 t2) = all id [stAll (<x) t1
                                  , stAll (>x) t2
                                  , wellFormed t1
                                  , wellFormed t2]

empty :: SearchTree a
empty = Leaf



-- Faustian stuff

--
-- length (faustianMap f xs) == length xs
-- faustianMap (f . g) xs == faustianMap f (faustianMap g xs)

faustianMap :: (a -> b) -> [a] -> [b]
faustianMap f [] = []
faustianMap f (a:as) = f a : replicate (length as) (f a)

sillyProp :: [a] -> Bool
sillyProp as = length as < 100

-- a new property approaches!
-- faustianMap id xs == xs

faustianMap' :: (a -> a) -> [a] -> [a]
faustianMap' _ as = as

2023-08-13 Sun 12:52

Announcements RSS